﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;

namespace Faml.Sources.XDR
{
    [OperationContainer]
    public static class XDROperations
    {
        private static Stream OpenStream(string path)
        {
            Stream fs = File.OpenRead(path);
            if (Path.GetExtension(path) == ".gzip")
                return new GZipStream(fs, CompressionMode.Decompress);
            else
                return fs;
        }

        public static T[,,] xdr3d<T>(string path, string variable)
        {
            Stream fs = OpenStream(path);
            try
            {
                XDRHeader hdr = new XDRHeader(fs);
                XDRReader reader = new XDRReader(fs);
                foreach(XDRVariable var in hdr.Variables) 
                    if(var.Name == variable) {
                        if (var.Dimensions != 3)
                            throw new InvalidOperationException("Variable " + variable + " is not 3D");
                        if(var.Type != typeof(T))
                            throw new InvalidOperationException("Variable " + variable + " has wrong type");
                        if (typeof(T) == typeof(double))
                            return (T[,,])reader.ReadFloat64(var, 0, 0, 0, var.GetLength(0), var.GetLength(1), var.GetLength(2));
                        else
                            throw new InvalidOperationException("This type is not supported");
                    } else
                        reader.Skip(var);
                throw new InvalidOperationException("XDR file has no variable named " + variable);
            }
            finally
            {
                fs.Close();
            }
        }

        public static T[, ,] xdr3d<T>(string path, string variable, int i0, int j0, int k0, int width, int height, int depth)
        {
            Stream fs = OpenStream(path);
            try
            {
                XDRHeader hdr = new XDRHeader(fs);
                XDRReader reader = new XDRReader(fs);
                foreach (XDRVariable var in hdr.Variables)
                    if (var.Name == variable)
                    {
                        if (var.Dimensions != 3)
                            throw new InvalidOperationException("Variable " + variable + " is not 3D");
                        if (var.Type != typeof(T))
                            throw new InvalidOperationException("Variable " + variable + " has wrong type");
                        if (width < 0)
                            width = var.GetLength(0);
                        if (height < 0)
                            height = var.GetLength(1);
                        if (depth < 0)
                            depth = var.GetLength(2);
                        if (typeof(T) == typeof(double))
                            return (T[, ,])reader.ReadFloat64(var, i0, j0, k0, width, height, depth);
                        else
                            throw new InvalidOperationException("This type is not supported");
                    }
                    else
                        reader.Skip(var);
                throw new InvalidOperationException("XDR file has no variable named " + variable);
            }
            finally
            {
                fs.Close();
            }
        }

        public static int GetVariableLength(string path, string variable,int idx)
        {
            Stream fs = OpenStream(path);
            try
            {
                XDRHeader hdr = new XDRHeader(fs);
                foreach (XDRVariable var in hdr.Variables)
                    if (var.Name == variable)
                    {
                        if (idx >= var.Dimensions )
                            throw new InvalidOperationException("Variable " + variable + " has no enough dimensions");
                        return var.GetLength(idx);
                    }
                throw new InvalidOperationException("XDR file has no variable named " + variable);
            }
            finally
            {
                fs.Close();
            }
        }

        public static T[] xdr1d<T>(string path, string variable)
        {
            Stream fs = OpenStream(path);
            try
            {
                XDRHeader hdr = new XDRHeader(fs);
                XDRReader reader = new XDRReader(fs);
                foreach (XDRVariable var in hdr.Variables)
                    if (var.Name == variable)
                    {
                        if (var.Dimensions != 1)
                            throw new InvalidOperationException("Variable " + variable + " is not 1D");
                        if (var.Type != typeof(T))
                            throw new InvalidOperationException("Variable " + variable + " has wrong type");
                        if (typeof(T) == typeof(double))
                            return (T[])reader.ReadFloat64(var);
                        else
                            throw new InvalidOperationException("This type is not supported");
                    }
                    else
                        reader.Skip(var);
                throw new InvalidOperationException("XDR file has no variable named " + variable);
            }
            finally
            {
                fs.Close();
            }
        }

        [OperationName("xdr1d")]
        public static double[] xdr1d(string path, string variable)
        {
            return xdr1d<double>(path, variable);
        }

        [OperationName("xdr3d")]
        public static double[, ,] xdr3d(string path, string variable)
        {
            return xdr3d<double>(path, variable);
        }
    }
}
